/*
 * This part is the most important part of the Frame.
 *
 * This file contain the IO engine and do most of the
 * stuff work for the module.Doing these stuff work automaticly
 * and transparently for the module can enhance the safety and
 * compability.That means the module writer just need to focus on 
 * the functions of his module.
 *
 */
#include <burst_kernel.h>


/*
 * bus_check_connect -Check the connecting status of bus_event_t structure.
 * @ev:		bus_event_t structure
 *
 * We check it by using getpeername because we can only get the remote
 * struct sockaddr structure when the connection was established.If there 
 * is no any connection or no client, getpeername will return -1.
 *
 * Return NULL means the connection was established, otherwise return -1.
 *
 */
static int bus_check_connect(bus_event_t *ev)
{

	int addr_len = sizeof(struct sockaddr);
	struct sockaddr_in sa = {0};

	if(getpeername(ev->sockfd, (struct sockaddr *)&sa, (int *)&addr_len) == -1) {
		return -1;
	}
	
	return 0;

}


/*
 * bus_event_get_buf - Get io buffer pointer from the bus_event_t structure.
 * @ev:		bus_event_t structure
 *
 * Return the ev->sender.buf_start;
 */
uint8_t *bus_event_get_buf(bus_event_t *ev)
{
	return ev->sender.buf_start;
}

/*
 * bus_event_get_size - Get io buffer size from the bus_event_t structure.
 * @ev:		bus_event_t structure
 *
 * Return the ev->sender.remain;
 */
int bus_event_get_size(bus_event_t *ev)
{
	return ev->sender.remain;
}
/*
 * bus_event_get_data - Get data from the bus_event_t structure.
 * @ev:		bus_event_t structure
 *
 * Return the ev->data;
 */
void *bus_event_get_data(bus_event_t *ev)
{
	return ev->data;
}

/*
 * bus_event_set_data - Set data from the bus_event_t structure.
 * @ev:		bus_event_t structure
 * @data:		The data pointer
 *
 */
void bus_event_set_data(bus_event_t *ev, void *data)
{
	ev->data = data;
}

/*
 * bus_callback - Call the callback function.
 * @ev:		bus_event_t structure
 */
void bus_callback(bus_event_t *ev)
{
	
	if(!ev->handler)
		return;
	ev->handler(ev);

}

/*
 * bus_get_callback - Get callback function pointer.
 * @ev:		bus_event_t structure
 */
bus_handle_event_t *bus_get_callback(bus_event_t *ev)
{
	
	return ev->handler;

}

/*
 * bus_set_callback - Set callback function pointer.
 * @ev:			bus_event_t structure
 * @handler:	The callback function pointer.
 */
void bus_set_callback(bus_event_t *ev, bus_handle_event_t *handler)
{
	
	ev->handler = handler;

}

/*
 * bus_get_socket - Safely get a bus_event_t structure from Kernel.
 * @type:		Socket type
 * @proto:		Socket protocol
 *
 * If succeed, return a bus_event_t structure, otherwise return NULL.
 */
bus_event_t *bus_get_socket(int type, int proto)
{

	bus_event_t *ev;
	int s = socket(AF_INET, type, proto);
	if(s < 0) {
		return NULL;
	}

	ev = (bus_event_t *)dlzalloc(sizeof(bus_event_t));
	if(!ev) {
		return NULL;
	}

	ev->sockfd = s;

	return ev;

}

/*
 * bus_close_socket - Safely close a bus_event_t structure from Kernel.
 * @ev:		The pointer of the bus_event_t structure.
 *
 */
void bus_close_socket(bus_event_t *ev)
{
	/*
	 * We have to delete the sockfd of ev from the event module.
	 */
	bus_event->del(0, ev);

	closesocket(ev->sockfd);

	/*
	 * Free the bus_event_t structure.
	 */
	dlfree(ev);

	return;

}

/*
 * bus_add_binding - Bind a bus_event_t structure from Kernel with a struct sockaddr_in structure.
 * @ev:		The pointer of the bus_event_t structure.
 * @sa:		The pointer of the struct sockaddr_in structure.
 *
 * If succeed, return NULL, otherwise return -1.
 */
int bus_add_binding(bus_event_t *ev, struct sockaddr_in *sa)
{

	return bus_io->bind(ev->sockfd, (struct sockaddr *)sa, sizeof(struct sockaddr));

}

/*
 * bus_add_sending - Add a sending io request on the bus_event_t structure from Kernel.
 * @ev:		The pointer of the bus_event_t structure.
 * @buf:	The Buffer.
 * @len:	The length of data.
 * @rsv:	Unused.
 *
 */
void bus_add_sending(bus_event_t *ev, 
				char *buf, 
				int len, 
				int rsv)
{

	ev->sender.bufptr = ev->sender.buf_start;
	ev->sender.remain = len;

	/*
	 * Copy the data to the io buffer.
	 */
	memcpy(ev->sender.buf_start, buf, len);

	bus_event_io_open(ev, BUS_IO_WRITING);

	return;

}

/*
 * bus_add_recving - Add a receiving io request on the bus_event_t structure from Kernel.
 * @ev:		The pointer of the bus_event_t structure.
 * @buf:	Unused.
 * @len:	Unused.
 * @rsv:	Unused.
 *
 */
void bus_add_recving(bus_event_t *ev, 
				char *buf, 
				int len, 
				int rsv)
{
	bus_event_io_open(ev, BUS_IO_READING);
	return;

}

/*
 * bus_add_connect - Add a connecting io request on the bus_event_t structure from Kernel.
 * @ev:			The pointer of the bus_event_t structure.
 * @sa:			The pointer of the struct sockaddr_in structure.
 * @addr_len:	Unused.
 *
 */
void bus_add_connecting(bus_event_t *ev, 
				struct sockaddr *sa,
				int addr_len)
{
	bus_event->add(0, ev);

	bus_io->set_non_block(ev->sockfd, 1);

	bus_event_io_open(ev, BUS_IO_CONNECTING);

	bus_io->connect(ev->sockfd, sa, sizeof(struct sockaddr));

	return;

}

/*
 * bus_add_accept - Add a accepting io request on the bus_event_t structure from Kernel.
 * @ev:			The pointer of the bus_event_t structure.
 * @sa:			The pointer of the struct sockaddr_in structure.
 * @addr_len:	Unused.
 *
 */
void bus_add_accepting(bus_event_t *ev, 
				struct sockaddr *sa,
				int addr_len)
{
	bus_event->add(0, ev);

	bus_io->set_non_block(ev->sockfd, 1);

	bus_event_io_open(ev, BUS_IO_ACCEPTING);

	bus_io->listen(ev->sockfd, 10);

	return;

}



/*
 * bus_process_sending - Process a sending io request on the bus_event_t structure from Kernel.
 * @ev:			The pointer of the bus_event_t structure.
 *
 */
static int bus_process_sending(bus_event_t *ev)
{
	int err;
	int ret = 0;

	if(bus_event_bit(ev, BUS_IO_WRITING)) {

		err = bus_io->send(ev->sockfd, \
						(char *)ev->sender.bufptr, \
						ev->sender.remain, \
						0);

		if(err <= 0) {

			bus_event->del(0, ev);

			ret = -1;
			bus_event_set(ev, BUS_IO_ERROR);

			bus_callback(ev);
			goto out;

		}

		ev->sender.bufptr += err;
		ev->sender.remain -= err;
		if(ev->sender.remain <= 0) {

			bus_event_io_close(ev, BUS_IO_WRITING);
			bus_callback(ev);

		}
		bus_event_unset(ev, BUS_IO_WRITING);
	}

out:
	if(ret < 0)
		bus_close_socket(ev);
	return ret;

}

/*
 * bus_process recving - Process a recving io request on the bus_event_t structure from Kernel.
 * @ev:			The pointer of the bus_event_t structure.
 *
 * Remark:	The received data is put into sender.buf_start.
 *			The size of data received is put into ev->sender.remain .
 */
static int bus_process_recving(bus_event_t *ev)
{
	int err;
	int ret = 0;

	if(bus_event_bit(ev, BUS_IO_READING)) {

		/* 
		 * We do this to check whether there is writing operation or not.
		 * We don't want to let the receive operation to replace the buf
		 * when where is writing operation.
		 * Just return NULL and report the caller as a succeeded IO operation.
		 * In fact we wont call the callback.
		 *
		 * PS: I 'm using Gedit only :) The high-lighting color is not as sharp as Emacs.
		 */
		if(bus_event_io_status(ev, BUS_IO_WRITING)) {
			goto out;
		}

		err = bus_io->recv(ev->sockfd, \
						(char *)ev->sender.buf_start, \
						BUS_BUF_SIZE, \
						0);

		if(err <= 0) {

			bus_event->del(0, ev);

			ret = -1;
			bus_event_set(ev, BUS_IO_ERROR);

			bus_callback(ev);
			goto out;

		}

		ev->sender.remain = err;

		bus_event_io_close(ev, BUS_IO_READING);

		bus_callback(ev);

		bus_event_unset(ev, BUS_IO_READING);

	}

out:
	if(ret < 0)
		bus_close_socket(ev);

	return ret;

}

/*
 * bus_process_connecting - Process a connecting io request on the bus_event_t structure from Kernel.
 * @ev:			The pointer of the bus_event_t structure.
 *
 */
static int bus_process_connecting(bus_event_t *ev)
{
	int ret = 0;

	if(bus_event_bit(ev, BUS_IO_CONNECTING)) {

		int tmp_size = sizeof(struct sockaddr);

		bus_event_io_close(ev, BUS_IO_CONNECTING);

		if(bus_check_connect(ev) < 0) {

			bus_event_set(ev, BUS_IO_ERROR);

			bus_callback(ev);

			bus_event_unset(ev, BUS_IO_CONNECTING);
			bus_close_socket(ev);

		} else {

			bus_callback(ev);

			bus_event_unset(ev, BUS_IO_CONNECTING);

		}

	}

out:
	return ret;

}

/*
 * bus_process_accepting - Process a accepting io request on the bus_event_t structure from Kernel.
 * @ev:			The pointer of the bus_event_t structure.
 *
 */
static int bus_process_accepting(bus_event_t *ev)
{
	int ret = 0;

	if(bus_event_bit(ev, BUS_IO_ACCEPTING)) {

		bus_event_t *leaf_ev = (bus_event_t *)dlzalloc(sizeof(bus_event_t));

		int tmp_size = sizeof(struct sockaddr);

		int getfd = bus_io->accept(ev->sockfd, (struct sockaddr *)&leaf_ev->sa, &tmp_size);
		if(getfd == SOCKET_ERROR) {

			ret = SOCKET_ERROR;

			dlfree(leaf_ev);

			goto out;

		}

		leaf_ev->sockfd = getfd;
		leaf_ev->father = ev;

		bus_set_callback(leaf_ev, ev->handler);
		bus_callback(leaf_ev);

		bus_event_unset(ev, BUS_IO_ACCEPTING);
	}

out:
	return ret;

}

void bus_pipe_handle(bus_event_t *ev)
{
	if(bus_event_io_status(ev, BUS_IO_WRITING))

		if(bus_event_bit(ev, BUS_IO_WRITING)) {

			bus_process_sending(ev);

		}

	if(bus_event_io_status(ev, BUS_IO_READING))

		if(bus_event_bit(ev, BUS_IO_READING)) {

			bus_process_recving(ev);

			bus_add_sending(ev->pipe.to, ev->sender.buf_start, ev->sender.remain, 0);

		}
}

/*
 * bus_engine_loop - The looping of the engine.
 * @it_is_not_available_now:		Unused.
 *
 */
void bus_engine_loop(void *it_is_not_available_now)
{
	int err;
	int ret = 0;

	struct list_head *first;
	struct list_head *list;
	bus_event_t *ev;

	for(;;) {

		if(!bus_event) {

			bus_panic("bus_engine_loop", "burst_buffered_io.c", 5000, 0xFEEEEEEE, "No module.");

		}

		first = list = bus_event->process(0);

		do {

			ev = (bus_event_t *)container_of(list, bus_event_t, list);
			
			if(bus_event_io_status(ev, BUS_IO_SLEEPING)) {

				goto skip_next_loop;

			}
			if(bus_event_io_status(ev, BUS_IO_READING)) {

				bus_process_recving(ev);

			}
			if(bus_event_io_status(ev, BUS_IO_WRITING)) {

				bus_process_sending(ev);

			}
			if(bus_event_io_status(ev, BUS_IO_ACCEPTING)) {

				bus_process_accepting(ev);

			}
			if(bus_event_io_status(ev, BUS_IO_CONNECTING)) {

				bus_process_connecting(ev);

			}

skip_next_loop:

			list = list->next;

		} while(list != first);

	}

err_out:
	return;

}


/*
 * bus_kernel - The kernel export function of the engine.
 *
 * We will give this to the module initializer.
 */
bus_kernel_t bus_kernel = {

	/* bus_event_get_buf_t */	
	&bus_event_get_buf, 

	/* bus_event_get_size_t */
	&bus_event_get_size, 

	/* bus_event_get_data_t */
	&bus_event_get_data, 

	/* bus_event_set_data_t */
	&bus_event_set_data,

	/* bus_callback_t */
	&bus_callback, 

	/* bus_get_callback_t */
	&bus_get_callback, 

	/* bus_set_callback_t */
	&bus_set_callback, 

	/* bus_get_socket_t */
	&bus_get_socket, 

	/* bus_add_binding_t */
	&bus_add_binding, 

	/* bus_add_sending_t */
	&bus_add_sending, 

	/* bus_add_recving_t */
	&bus_add_recving, 

	/* bus_add_connecting_t */
	&bus_add_connecting, 

	/* bus_add_accepting_t */
	&bus_add_accepting, 

	/* bus_engine_loop_t */
	&bus_engine_loop

};
